#include "gd32w51x.h"
#include "stdio.h"
#include "string.h"
#include "DevicesQueue.h"
#include "DevicesIFRP.h"

void vIFRPInit(void)
{
    vIFRPEncodeInit();
    vIFRPDecodeInit();
}

void vIFRPEncodeInit(void)
{
    timer_oc_parameter_struct timer_ocintpara = {0};
    timer_parameter_struct timer_initpara = {0};

    rcu_periph_clock_enable(RCU_TIMER1);
    rcu_periph_clock_enable(RCU_TIMER2);
    rcu_periph_clock_enable(RCU_GPIOB);

    gpio_mode_set(GPIOB, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_5);
    gpio_output_options_set(GPIOB, GPIO_OTYPE_PP, GPIO_OSPEED_25MHZ, GPIO_PIN_5);
    gpio_af_set(GPIOB, GPIO_AF_1, GPIO_PIN_5);


    /* 定时器1当作载波信号 */
    timer_deinit(TIMER1);

    /* TIMER configuration */
    timer_initpara.prescaler         = 1 - 1;
    timer_initpara.alignedmode       = TIMER_COUNTER_EDGE;
    timer_initpara.counterdirection  = TIMER_COUNTER_UP;
    timer_initpara.period            = (SystemCoreClock / 38000) - 1;
    timer_initpara.clockdivision     = TIMER_CKDIV_DIV1;
    timer_initpara.repetitioncounter = 0;
    timer_init(TIMER1, &timer_initpara);

    timer_ocintpara.outputstate  = TIMER_CCX_ENABLE;
    timer_ocintpara.outputnstate = TIMER_CCXN_DISABLE;
    timer_ocintpara.ocpolarity   = TIMER_OC_POLARITY_HIGH;
    timer_ocintpara.ocnpolarity  = TIMER_OCN_POLARITY_HIGH;
    timer_ocintpara.ocidlestate  = TIMER_OC_IDLE_STATE_LOW;
    timer_ocintpara.ocnidlestate = TIMER_OCN_IDLE_STATE_LOW;
    timer_channel_output_config(TIMER1, TIMER_CH_3, &timer_ocintpara);

    /* CH0 configuration in PWM mode0,duty cycle 25% */
    timer_channel_output_pulse_value_config(TIMER1, TIMER_CH_3, 0);
    timer_channel_output_mode_config(TIMER1, TIMER_CH_3, TIMER_OC_MODE_PWM0);
    timer_channel_output_shadow_config(TIMER1, TIMER_CH_3, TIMER_OC_SHADOW_DISABLE);

    /* auto-reload preload enable */
    timer_auto_reload_shadow_enable(TIMER1);
    /* enable a TIMER */
    timer_enable(TIMER1);


    /* 定时器2当作包络信号 */
    timer_deinit(TIMER2);

    /* TIMER configuration */
    timer_initpara.prescaler         = (SystemCoreClock / 1000000) - 1;
    timer_initpara.alignedmode       = TIMER_COUNTER_EDGE;
    timer_initpara.counterdirection  = TIMER_COUNTER_UP;
    timer_initpara.period            = 65536 - 1;
    timer_initpara.clockdivision     = TIMER_CKDIV_DIV1;
    timer_initpara.repetitioncounter = 0;
    timer_init(TIMER2, &timer_initpara);

    timer_ocintpara.outputstate  = TIMER_CCX_ENABLE;
    timer_ocintpara.outputnstate = TIMER_CCXN_DISABLE;
    timer_ocintpara.ocpolarity   = TIMER_OC_POLARITY_HIGH;
    timer_ocintpara.ocnpolarity  = TIMER_OCN_POLARITY_HIGH;
    timer_ocintpara.ocidlestate  = TIMER_OC_IDLE_STATE_LOW;
    timer_ocintpara.ocnidlestate = TIMER_OCN_IDLE_STATE_LOW;
    timer_channel_output_config(TIMER2, TIMER_CH_3, &timer_ocintpara);

    /* CH0 configuration in PWM mode0,duty cycle 25% */
    timer_channel_output_pulse_value_config(TIMER2, TIMER_CH_3, 50000);
    timer_channel_output_mode_config(TIMER2, TIMER_CH_3, TIMER_OC_MODE_PWM0);
    timer_channel_output_shadow_config(TIMER2, TIMER_CH_3, TIMER_OC_SHADOW_DISABLE);

    timer_primary_output_config(TIMER2, ENABLE);

    nvic_irq_enable(TIMER2_IRQn, 0, 0);

    /* clear interrupt bit */
    timer_interrupt_flag_clear(TIMER2, TIMER_INT_FLAG_CH3);
    /* enable the TIMER interrupt */
    timer_interrupt_enable(TIMER2, TIMER_INT_CH3);

    /* auto-reload preload enable */
    timer_auto_reload_shadow_enable(TIMER2);
    /* enable a TIMER */
    timer_enable(TIMER2);
}

void vIFRPEncodeMachine(void)
{
    uint8_t ucByte = IFPRStop;
    volatile static IFRPEncodeStateEnum st_EnumMachineState = IFPRIdle;

    TIMER_CNT(TIMER2) -= TIMER_CH3CV(TIMER2);

    switch(st_EnumMachineState)
    {
        case IFPRStart:
            TIMER_CH3CV(TIMER2) = (uint32_t)(9000 - 1);
            TIMER_CH3CV(TIMER1) = TIMER_CAR(TIMER1) / 2;
            st_EnumMachineState = IFPRStartLow;
            break;

        case IFPRStartLow:
            TIMER_CH3CV(TIMER2) = (uint32_t)(4500 - 1);
            TIMER_CH3CV(TIMER1) = 0;
            enumQueuePopByte(&g_TypeQueueIFRPEncode, &ucByte);
            st_EnumMachineState = ucByte;
            break;

        case IFPRRepeat:
            TIMER_CH3CV(TIMER2) = (uint32_t)(9000 - 1);
            TIMER_CH3CV(TIMER1) = TIMER_CAR(TIMER1) / 2;
            st_EnumMachineState = IFPRRepeatLow;
            break;

        case IFPRRepeatLow:
            TIMER_CH3CV(TIMER2) = (uint32_t)(2240 - 1);
            TIMER_CH3CV(TIMER1) = 0;
            st_EnumMachineState = IFPRRepeatEnd;
            break;

        case IFPRRepeatEnd:
            TIMER_CH3CV(TIMER2) = (uint32_t)(560 - 1);
            TIMER_CH3CV(TIMER1) = TIMER_CAR(TIMER1) / 2;
            enumQueuePopByte(&g_TypeQueueIFRPEncode, &ucByte);
            st_EnumMachineState = ucByte;
            break;

        case IFPRLogical1:
            TIMER_CH3CV(TIMER2) = (uint32_t)(560 - 1);
            TIMER_CH3CV(TIMER1) = TIMER_CAR(TIMER1) / 2;
            st_EnumMachineState = IFPRLogical1Low;
            break;

        case IFPRLogical1Low:
            TIMER_CH3CV(TIMER2) = (uint32_t)(1680 - 1);
            TIMER_CH3CV(TIMER1) = 0;
            enumQueuePopByte(&g_TypeQueueIFRPEncode, &ucByte);
            st_EnumMachineState = ucByte;
            break;

        case IFPRLogical0:
            TIMER_CH3CV(TIMER2) = (uint32_t)(560 - 1);
            TIMER_CH3CV(TIMER1) = TIMER_CAR(TIMER1) / 2;
            st_EnumMachineState = IFPRLogical0Low;
            break;

        case IFPRLogical0Low:
            TIMER_CH3CV(TIMER2) = (uint32_t)(560 - 1);
            TIMER_CH3CV(TIMER1) = 0;
            enumQueuePopByte(&g_TypeQueueIFRPEncode, &ucByte);
            st_EnumMachineState = ucByte;
            break;

        case IFPRStop:
        case IFPRIdle:
            TIMER_CH3CV(TIMER2) = (uint32_t)(10000 - 1);
            TIMER_CH3CV(TIMER1) = 0;
            enumQueuePopByte(&g_TypeQueueIFRPEncode, &ucByte);
            st_EnumMachineState = ucByte;
            break;

        default : st_EnumMachineState = IFPRStop; break;
    }
}

int8_t cIFRPEncodeSendDatas(uint8_t *pucDatas, int32_t iLength)
{
    uint8_t ucMask = 0x80;
    int8_t cByteDecodeBuff[8] = {0}, i = 0;

    if((pucDatas == NULL) || (iLength < 0))
        return 1;

    enumQueuePushByte(&g_TypeQueueIFRPEncode, IFPRStart);

    while((iLength--) > 0)
    {
        for(ucMask = 0x80, i = 0; ucMask; ucMask >>= 1)
        {
            cByteDecodeBuff[i++] = (*pucDatas & ucMask) ? IFPRLogical1 : IFPRLogical0;
        }

        if(enumQueuePushDatas(&g_TypeQueueIFRPEncode, cByteDecodeBuff, 8) != queueNormal)
        {
            return 2;
        }

        ++pucDatas;
    }

    enumQueuePushByte(&g_TypeQueueIFRPEncode, IFPRStop);

    return 0;
}

void vIFRPDecodeInit(void)
{
    /* enable the gpio clock */
    rcu_periph_clock_enable(RCU_GPIOB);
    /* enable the CFGCMP clock */
    rcu_periph_clock_enable(RCU_SYSCFG);

    /* configure pin as input */
    gpio_mode_set(GPIOB, GPIO_MODE_INPUT, GPIO_PUPD_PULLUP, GPIO_PIN_7);

    /* enable and set EXTI interrupt to the specified priority */
    nvic_irq_enable(EXTI5_9_IRQn, 1, 0);

    /* connect key EXTI line to GPIO pin */
    syscfg_exti_line_config(EXTI_SOURCE_GPIOB, EXTI_SOURCE_PIN7);

    /* configure EXTI line */
    exti_init(EXTI_7, EXTI_INTERRUPT, EXTI_TRIG_FALLING);

    exti_interrupt_flag_clear(EXTI_7);
}

#if 1

int8_t cIFRPDecode(IFRPCodeType *ptypeData, int16_t sValue)
{
    uint8_t ucValue = 0;

    if((sValue > IFRP_DECODE_LOW_MIN) && (sValue < IFRP_DECODE_LOW_MAX))
        ucValue = 0;
    else if((sValue > IFRP_DECODE_HIGH_MIN) && (sValue < IFRP_DECODE_HIGH_MAX))
        ucValue = 1;
    else if((sValue > IFRP_DECODE_REPEAT_MIN) && (sValue < IFRP_DECODE_REPEAT_MAX))
        ptypeData->state = necRepeat;
    else
        ptypeData->state = necReset;

    ++ptypeData->length;

    switch(ptypeData->state)
    {
        case necReadUser:
            ptypeData->data = (ptypeData->length == 1) ? ucValue : ((ptypeData->data << 1) | ucValue);
            ptypeData->state = (ptypeData->length >= 32) ? necSucceed : ptypeData->state;
            break;

        case necRepeat: break;

        default:
            ptypeData->length = 0;
            ptypeData->state = necReadUser;
            break;
    }

    // if(ptypeData->state == necSucceed)
    //     printf("length: %d, data: %08X\r\n", ptypeData->length, ptypeData->data);

    return ptypeData->state;
}

#elif 1

int8_t cIFRPDecode(IFRPCodeType *ptypeData, int16_t sValue)
{
    uint8_t ucValue = 0;

    if((sValue > IFRP_DECODE_LOW_MIN) && (sValue < IFRP_DECODE_LOW_MAX))
        ucValue = 0;
    else if((sValue > IFRP_DECODE_HIGH_MIN) && (sValue < IFRP_DECODE_HIGH_MAX))
        ucValue = 1;
    else
        ptypeData->state = necReset;

    ++ptypeData->length;

    switch(ptypeData->state)
    {
        case necReset:
            memset(ptypeData, 0, sizeof(IFRPCodeType));
            ptypeData->state = necReadUser;
            break;

        case necReadUser:
            ptypeData->user = (ptypeData->user << 1) | ucValue;
            if(ptypeData->length >= 4)
                ptypeData->state = necSucceed;
            break;

        default: ptypeData->state = necReadUser; break;
    }

    if(ptypeData->state == necSucceed)
        printf("length: %d, user: %02X\r\n", ptypeData->length, ptypeData->user);

    return ptypeData->state;
}

#elif 0

int8_t cIFRPDecode(IFRPCodeType *ptypeData, int16_t sValue)
{
    uint8_t ucValue = 0;

    if((sValue > IFRP_DECODE_LOW_MIN) && (sValue < IFRP_DECODE_LOW_MAX))
        ucValue = 0;
    else if((sValue > IFRP_DECODE_HIGH_MIN) && (sValue < IFRP_DECODE_HIGH_MAX))
        ucValue = 1;
    else
        ptypeData->state = necReset;

    ++ptypeData->length;

    switch(ptypeData->state)
    {
        case necReset:
            memset(ptypeData, 0, sizeof(IFRPCodeType));
            ptypeData->state = necReadUser;
            break;

        case necReadUser:
            ptypeData->user = (ptypeData->user << 1) | ucValue;
            if(ptypeData->length >= 8)
                ptypeData->state = necReadControl;
            break;

        case necReadControl:
            ptypeData->control = (ptypeData->control << 1) | ucValue;
            if(ptypeData->length >= 16)
                ptypeData->state = necReadData;
            break;

        case necReadData:
            if(ptypeData->control == 0xA5)
            {
                /* 低位先发送、先接收 */
                ptypeData->data |= ucValue << (ptypeData->length - 17);
                if(ptypeData->length >= 32)
                    ptypeData->state = necSucceed;
                // ptypeData->data = (ptypeData->data << 1) | ucValue;
                // if(ptypeData->length >= 32)
                //     ptypeData->state = necSucceed;
            }
            else
            {
                /* 低位先发送、先接收 */
                ptypeData->data |= ucValue << (ptypeData->length - 17);
                if(ptypeData->length >= 48)
                    ptypeData->state = necSucceed;
            }
            break;

        default: ptypeData->state = necReadUser; break;
    }

    // if(ptypeData->state == necSucceed)
    //     printf("length: %d, user: %02X, control: %02X, data: %08X\r\n", ptypeData->length, ptypeData->user, ptypeData->control, ptypeData->data);

    return ptypeData->state;
}

#elif 0

int8_t cIFRPDecode(IFRPCodeType *ptypeData, int16_t sValue)
{
    uint8_t ucValue = 0;

    if((sValue > IFRP_DECODE_LOW_MIN) && (sValue < IFRP_DECODE_LOW_MAX))
        ucValue = 0;
    else if((sValue > IFRP_DECODE_HIGH_MIN) && (sValue < IFRP_DECODE_HIGH_MAX))
        ucValue = 1;
    else
        ptypeData->state = necReset;

    ++ptypeData->length;

    switch(ptypeData->state)
    {
        case necReset:
            memset(ptypeData, 0, sizeof(IFRPCodeType));
            ptypeData->state = necMode0;
            break;

        case necMode0:
            ptypeData->mode0 = (ptypeData->mode0 << 1) | (ucValue ? 0x01 : 0);
            if(ptypeData->length >= 8)
            {
                ptypeData->state = necMode1;
                ptypeData->length = 0;
            }
            break;

        case necMode1:
            ptypeData->mode1 = (ptypeData->mode1 << 1) | (ucValue ? 0x01 : 0);
            if(ptypeData->length >= 8)
            {
                ptypeData->state = necData;
                ptypeData->length = 0;
            }
            break;

        case necData:
            if(ptypeData->mode0 == 0x5A)
            {
                ptypeData->datas[0] = (ptypeData->datas[0] << 1) | (ucValue ? 0x01 : 0);
                if(ptypeData->length >= 8)
                {
                    ptypeData->state = necCrc;
                    ptypeData->length = 0;
                }
            }
            else
            {
                ptypeData->datas[(ptypeData->length - 1) >> 3] >>= 1;
                ptypeData->datas[(ptypeData->length - 1) >> 3]  |= (ucValue ? 0x80 : 0);
                if(ptypeData->length >= 72)
                {
                    ptypeData->state = necCrc;
                    ptypeData->length = 0;
                }
            }
            break;

        case necCrc:
            ptypeData->crc = (ptypeData->crc << 1) | (ucValue ? 0x01 : 0);
            if(ptypeData->length >= 8)
                ptypeData->state = necSucceed;
            break;

        default: ptypeData->state = necReset; break;
    }

    if(ptypeData->state == necSucceed)
    {
        ptypeData->timeNow      = ((uint16_t)(ptypeData->datas[0] & 0x0F) << 8) + ptypeData->datas[1];
        ptypeData->timeNow      = ((ptypeData->timeNow / 60) << 8) + ptypeData->timeNow % 60;
        ptypeData->timeClock[0] = ((uint16_t)(ptypeData->datas[2] / 4) << 8) + (ptypeData->datas[2] & 0x03) * 15;
        ptypeData->timeClock[1] = ((uint16_t)(ptypeData->datas[3] / 4) << 8) + (ptypeData->datas[3] & 0x03) * 15;
        ptypeData->timeClock[2] = ((uint16_t)(ptypeData->datas[4] / 4) << 8) + (ptypeData->datas[4] & 0x03) * 15;
        ptypeData->timeClock[3] = ((uint16_t)(ptypeData->datas[5] / 4) << 8) + (ptypeData->datas[5] & 0x03) * 15;
        ptypeData->timeClock[4] = ((uint16_t)(ptypeData->datas[6] / 4) << 8) + (ptypeData->datas[6] & 0x03) * 15;
        ptypeData->timeClock[5] = ((uint16_t)(ptypeData->datas[7] / 4) << 8) + (ptypeData->datas[7] & 0x03) * 15;
        ptypeData->timeClock[6] = ((uint16_t)(ptypeData->datas[8] / 4) << 8) + (ptypeData->datas[8] & 0x03) * 15;

        printf("\r\nlength: %d, mode0: %02X, mode1: %02X, datas:", ptypeData->length, ptypeData->mode0, ptypeData->mode1);
        for(int i = 0; i < 9; ++i)
        {
            printf(" %02X", ptypeData->datas[i]);
        }
        printf(", crc: %02X\r\n", ptypeData->crc);

        printf("time now: %02d:%02d\r\n", ptypeData->timeNow >> 8, ptypeData->timeNow & 0xFF);
        for(int i = 0; i < 7; ++i)
        {
            printf("clock %d: %02d:%02d\r\n", i + 1, ptypeData->timeClock[i] >> 8, ptypeData->timeClock[i] & 0xFF);
        }
    }

    return ptypeData->state;
}

#endif
